<template>
<div  class="zh-body">
    <div  id="zhWaves" class="zhWaves">
    </div>
    <LayoutParentView />
</div>
</template>
<script lang="ts">
import LayoutParentView from '@/layout/routerView/parent.vue';
import { onMounted,onUnmounted } from 'vue';
export default {
    name: 'loginIndex',
    components: { LayoutParentView },
    setup() {
		class ShaderProgram {

            constructor( holder, options = {} ) {

                options = Object.assign( {
                antialias: false,
                depthTest: false,
                mousemove: false,
                autosize: true,
                side: 'front',
                vertex: `
                    precision highp float;

                    attribute vec4 a_position;
                    attribute vec4 a_color;

                    uniform float u_time;
                    uniform vec2 u_resolution;
                    uniform vec2 u_mousemove;
                    uniform mat4 u_projection;

                    varying vec4 v_color;

                    void main() {

                    gl_Position = u_projection * a_position;
                    gl_PointSize = (10.0 / gl_Position.w) * 100.0;

                    v_color = a_color;

                    }`,
                fragment: `
                    precision highp float;

                    uniform sampler2D u_texture;
                    uniform int u_hasTexture;

                    varying vec4 v_color;

                    void main() {

                    if ( u_hasTexture == 1 ) {

                        gl_FragColor = v_color * texture2D(u_texture, gl_PointCoord);

                    } else {

                        gl_FragColor = v_color;

                    }

                    }`,
                uniforms: {},
                buffers: {},
                camera: {},
                texture: null,
                onUpdate: ( () => {} ),
                onResize: ( () => {} ),
                }, options )

                const uniforms = Object.assign( {
                time: { type: 'float', value: 0 },
                hasTexture: { type: 'int', value: 0 },
                resolution: { type: 'vec2', value: [ 0, 0 ] },
                mousemove: { type: 'vec2', value: [ 0, 0 ] },
                projection: { type: 'mat4', value: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] },
                }, options.uniforms )

                const buffers = Object.assign( {
                position: { size: 3, data: [] },
                color: { size: 4, data: [] },
                }, options.buffers )

                const camera = Object.assign( {
                fov: 60,
                near: 1,
                far: 10000,
                aspect: 1,
                z: 100,
                perspective: true,
                }, options.camera )

                const canvas = document.createElement( 'canvas' )
                const gl = canvas.getContext( 'webgl', { antialias: options.antialias } )

                if ( ! gl ) return false

                this.count = 0
                this.gl = gl
                this.canvas = canvas
                this.camera = camera
                this.holder = holder
                this.onUpdate = options.onUpdate
                this.onResize = options.onResize
                this.data = {}

                holder.appendChild( canvas )

                this.createProgram( options.vertex, options.fragment )

                this.createBuffers( buffers )
                this.createUniforms( uniforms )

                this.updateBuffers()
                this.updateUniforms()

                this.createTexture( options.texture )

                gl.enable( gl.BLEND )
                gl.enable( gl.CULL_FACE )
                gl.blendFunc( gl.SRC_ALPHA, gl.ONE )
                gl[ options.depthTest ? 'enable' : 'disable' ]( gl.DEPTH_TEST )

                if ( options.autosize )
                window.addEventListener( 'resize', e => this.resize( e ), false )
                if ( options.mousemove )
                window.addEventListener( 'mousemove', e => this.mousemove( e ), false )

                this.resize()

                this.update = this.update.bind( this )
                this.time = { start: performance.now(), old: performance.now() }
                this.update()

            }

            mousemove( e ) {

                let x = e.pageX / this.width * 2 - 1
                let y = e.pageY / this.height * 2 - 1

                this.uniforms.mousemove = [ x, y ]

            }

            resize() {

                const holder = this.holder
                const canvas = this.canvas
                const gl = this.gl

                const width = this.width = holder.offsetWidth
                const height = this.height = holder.offsetHeight
                const aspect = this.aspect = width / height
                const dpi = this.dpi = devicePixelRatio

                canvas.width = width * dpi
                canvas.height = height * dpi
                canvas.style.width = width + 'px'
                canvas.style.height = height + 'px'

                gl.viewport( 0, 0, width * dpi, height * dpi )
                gl.clearColor( 0, 0, 0, 0 )

                this.uniforms.resolution = [ width, height ]
                this.uniforms.projection = this.setProjection( aspect )

                this.onResize( width, height, dpi )

            }

            setProjection( aspect ) {

                const camera = this.camera

                if ( camera.perspective ) {

                camera.aspect = aspect

                const fovRad = camera.fov * ( Math.PI / 180 )
                const f = Math.tan( Math.PI * 0.5 - 0.5 * fovRad )
                const rangeInv = 1.0 / ( camera.near - camera.far )

                const matrix = [
                    f / camera.aspect, 0, 0, 0,
                    0, f, 0, 0,
                    0, 0, (camera.near + camera.far) * rangeInv, -1,
                    0, 0, camera.near * camera.far * rangeInv * 2, 0
                ]

                matrix[ 14 ] += camera.z
                matrix[ 15 ] += camera.z

                return matrix

                } else {

                return [
                    2 / this.width, 0, 0, 0,
                    0, -2 / this.height, 0, 0,
                    0, 0, 1, 0,
                    -1, 1, 0, 1,
                ]

                }

            }

            createShader( type, source ) {

                const gl = this.gl
                const shader = gl.createShader( type )

                gl.shaderSource( shader, source )
                gl.compileShader( shader )

                if ( gl.getShaderParameter (shader, gl.COMPILE_STATUS ) ) {

                return shader

                } else {

                console.log( gl.getShaderInfoLog( shader ) )
                gl.deleteShader( shader )

                }

            }

            createProgram( vertex, fragment ) {

                const gl = this.gl

                const vertexShader = this.createShader( gl.VERTEX_SHADER, vertex )
                const fragmentShader = this.createShader( gl.FRAGMENT_SHADER, fragment )

                const program = gl.createProgram()

                gl.attachShader( program, vertexShader )
                gl.attachShader( program, fragmentShader )
                gl.linkProgram( program )

                if ( gl.getProgramParameter( program, gl.LINK_STATUS ) ) {

                gl.useProgram( program )
                this.program = program

                } else {

                console.log( gl.getProgramInfoLog( program ) )
                gl.deleteProgram( program )

                }

            }

            createUniforms( data ) {

                const gl = this.gl
                const uniforms = this.data.uniforms = data
                const values = this.uniforms = {}

                Object.keys( uniforms ).forEach( name => {

                const uniform = uniforms[ name ]

                uniform.location = gl.getUniformLocation( this.program, 'u_' + name )

                Object.defineProperty( values, name, {
                    set: value => {

                    uniforms[ name ].value = value
                    this.setUniform( name, value )

                    },
                    get: () => uniforms[ name ].value
                } )

                } )

            }

            setUniform( name, value ) {

                const gl = this.gl
                const uniform = this.data.uniforms[ name ]

                uniform.value = value

                switch ( uniform.type ) {
                case 'int': {
                    gl.uniform1i( uniform.location, value )
                    break
                }
                case 'float': {
                    gl.uniform1f( uniform.location, value )
                    break
                }
                case 'vec2': {
                    gl.uniform2f( uniform.location, ...value )
                    break
                }
                case 'vec3': {
                    gl.uniform3f( uniform.location, ...value )
                    break
                }
                case 'vec4': {
                    gl.uniform4f( uniform.location, ...value )
                    break
                }
                case 'mat2': {
                    gl.uniformMatrix2fv( uniform.location, false, value )
                    break
                }
                case 'mat3': {
                    gl.uniformMatrix3fv( uniform.location, false, value )
                    break
                }
                case 'mat4': {
                    gl.uniformMatrix4fv( uniform.location, false, value )
                    break
                }
                }

                // ivec2       : uniform2i,
                // ivec3       : uniform3i,
                // ivec4       : uniform4i,
                // sampler2D   : uniform1i,
                // samplerCube : uniform1i,
                // bool        : uniform1i,
                // bvec2       : uniform2i,
                // bvec3       : uniform3i,
                // bvec4       : uniform4i,

            }

            updateUniforms() {

                const uniforms = this.data.uniforms

                Object.keys( uniforms ).forEach( name => {

                const uniform = uniforms[ name ]

                this.uniforms[ name ] = uniform.value

                } )

            }

            createBuffers( data ) {

                const buffers = this.data.buffers = data
                const values = this.buffers = {}

                Object.keys( buffers ).forEach( name => {

                const buffer = buffers[ name ]

                buffer.buffer = this.createBuffer( 'a_' + name, buffer.size )

                Object.defineProperty( values, name, {
                    set: data => {

                    buffers[ name ].data = data
                    this.setBuffer( name, data )

                    if ( name == 'position' )
                        this.count = buffers.position.data.length / 3

                    },
                    get: () => buffers[ name ].data
                } )

                } )

            }

            createBuffer( name, size ) {

                const gl = this.gl
                const program = this.program

                const index = gl.getAttribLocation( program, name )
                const buffer = gl.createBuffer()

                gl.bindBuffer( gl.ARRAY_BUFFER, buffer )
                gl.enableVertexAttribArray( index )
                gl.vertexAttribPointer( index, size, gl.FLOAT, false, 0, 0 )

                return buffer

            }

            setBuffer( name, data ) {

                const gl = this.gl
                const buffers = this.data.buffers

                if ( name == null && ! gl.bindBuffer( gl.ARRAY_BUFFER, null ) ) return

                gl.bindBuffer( gl.ARRAY_BUFFER, buffers[ name ].buffer )
                gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( data ), gl.STATIC_DRAW )

            }

            updateBuffers() {

                const buffers = this.buffers

                Object.keys( buffers ).forEach( name =>{
                    const buffer = buffers[ name ]
                    buffers[ name ] = buffer.data
                })

                this.setBuffer( null )

            }

            createTexture( src ) {

                const gl = this.gl
                const texture = gl.createTexture()

                gl.bindTexture( gl.TEXTURE_2D, texture )
                gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array( [ 0, 0, 0, 0 ] ) )

                this.texture = texture

                if ( src ) {

                this.uniforms.hasTexture = 1
                this.loadTexture( src )

                }

            }

            loadTexture( src ) {

                const gl = this.gl
                const texture = this.texture

                const textureImage = new Image()

                textureImage.onload = () => {

                gl.bindTexture( gl.TEXTURE_2D, texture )

                gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImage )

                gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR )
                gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR )

                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)

                // gl.generateMipmap( gl.TEXTURE_2D )

                }

                textureImage.src = src

            }

            update() {

                const gl = this.gl

                const now = performance.now()
                const elapsed = ( now - this.time.start ) / 5000
                const delta = now - this.time.old
                this.time.old = now

                this.uniforms.time = elapsed

                if ( this.count > 0 ) {
                //gl.clear( gl.COLORBUFFERBIT )
                gl.drawArrays( gl.POINTS, 0, this.count )
                }
                

                this.onUpdate( delta )

                requestAnimationFrame( this.update )

            }

        }
        let ShaderProgramData=null;
        onMounted(() => {
            const pointSize = 2.5
            const zhWaves=document.querySelector( '.zhWaves' );
            ShaderProgramData= new ShaderProgram( zhWaves, {
            texture: '',
            uniforms: {
                size: { type: 'float', value: pointSize },
                field: { type: 'vec3', value: [ 0, 0, 0 ] },
                speed: { type: 'float', value: 5 },
            },
            vertex: `
                #define M_PI 3.1415926535897932384626433832795

                precision highp float;

                attribute vec4 a_position;
                attribute vec4 a_color;

                uniform float u_time;
                uniform float u_size;
                uniform float u_speed;
                uniform vec3 u_field;
                uniform mat4 u_projection;

                varying vec4 v_color;

                void main() {

                vec3 pos = a_position.xyz;

                pos.y += (
                    cos(pos.x / u_field.x * M_PI * 8.0 + u_time * u_speed) +
                    sin(pos.z / u_field.z * M_PI * 8.0 + u_time * u_speed)
                ) * u_field.y;

                gl_Position = u_projection * vec4( pos.xyz, a_position.w );
                gl_PointSize = ( u_size / gl_Position.w ) * 100.0;

                v_color = a_color;

                }`,
            fragment: `
                precision highp float;

                uniform sampler2D u_texture;

                varying vec4 v_color;

                void main() {

                gl_FragColor = v_color * texture2D(u_texture, gl_PointCoord);

                }`,
            onResize( w, h, dpi ) {

                const position = [], color = []

                const width = 400 * ( w / h )
                const depth = 400
                const height = 3
                const distance = 5

                for ( let x = 0; x < width; x += distance ) {
                for ( let z = 0; z < depth; z+= distance ) {

                    position.push( - width / 2 + x, -30, -depth / 2 + z )
                    color.push( 0, 1 - ( x / width ) * 1, 0.5 + x / width * 0.5, z / depth )

                }
                }
                
                this.uniforms.field = [ width, height, depth ]

                this.buffers.position = position
                this.buffers.color = color

                this.uniforms.size = ( h / 400) * pointSize * dpi

            },
            } )
        })

        onUnmounted(() => {
            if(ShaderProgramData){
                window.removeEventListener('resize', e => ShaderProgramData.resize( e ));
                window.removeEventListener('mousemove', e => ShaderProgramData.mousemove( e ));
            }
            
        });
        const option = {
				grid: {
					top: 50,
					right: 20,
					bottom: 30,
					left: 30,
				},
				tooltip: {
					trigger: 'item',
				},
				series: [
					{
						name: '面积模式',
						type: 'pie',
						radius: [20, 50],
						center: ['50%', '50%'],
						roseType: 'area',
						itemStyle: {
							borderRadius: 8,
						},
						data: [
							{ value: 40, name: '监测设备预警' },
							{ value: 38, name: '天气预警' },
							{ value: 32, name: '任务预警' },
							{ value: 30, name: '病虫害预警' },
						],
					},
				],
			};
        return {
			option
		};
	},
};

</script>

<style scoped lang="scss">
.zh-body{height: 100vh;position: relative;background-color: #000;}

canvas {
	display:block;
}
.zhWaves {
	position:absolute;
	left:0;
	top:0;
	right:0;
	bottom:0;
}
</style>